package model

import (
    "git.inspur.com/x/models"
    "git.inspur.com/x/iam-adapter-go/resource"
    "strings"
)

const (
    ProtocolHTTP  = "HTTP"
    ProtocolHTTPS = "HTTPS"
)

type DomainPage struct {
    TotalCount int64     `json:"totalCount" valid:"-"`
    PageNo     int       `json:"pageNo" valid:"-"`
    PageSize   int       `json:"pageSize" valid:"-"`
    Data       []*Domain `json:"data" valid:"-"`
}

type Domain struct {
    Id              string      `xorm:"pk" json:"id" valid:"-" `
    Creator         string      `json:"creator" valid:"-"`
    CreatorName     string      `json:"creatorName" valid:"-"`
    A5tId           string      `xorm:"account_id" json:"accountId" valid:"-"`
    A5tName         string      `xorm:"account_name" json:"accountName" valid:"-"`
    DomainName      string      `json:"domainName" valid:"-"`
    Protocol        string      `json:"protocol" valid:"-"`
    RouteConfig     string      `json:"routeConfig" valid:"-"`
    CreateTime      models.Time `xorm:"created" json:"createTime" valid:"-"`
    UpdateTime      models.Time `xorm:"updated" json:"updateTime" valid:"-"`
    DeleteTime      models.Time `xorm:"deleted" json:"deleteTime" valid:"-"`
    Cert            *Cert       `json:"-" valid:"-" xorm:"-"`
    CertName        string      `json:"certName" valid:"-" xorm:"-"`
    CertCertificate string      `json:"certCertificate" valid:"-" xorm:"-"`
    CertKey         string      `json:"certKey" valid:"-" xorm:"-"`
}

type Cert struct {
    Id          string      `xorm:"pk" json:"id" valid:"-" `
    Creator     string      `json:"creator" valid:"-"`
    CreatorName string      `json:"creatorName" valid:"-"`
    A5tId       string      `xorm:"account_id" json:"accountId" valid:"-"`
    A5tName     string      `xorm:"account_name" json:"accountName" valid:"-"`
    DomainId    string      `json:"domainId" valid:"-" `
    Name        string      `json:"name" valid:"-" `
    Certificate string      `json:"certificate" valid:"-" `
    Key         string      `json:"key" valid:"-" `
    CreateTime  models.Time `xorm:"created" json:"createTime" valid:"-" `
    UpdateTime  models.Time `xorm:"updated" json:"updateTime" valid:"-" `
}

type DomainIngressRouteConfig struct {
    Path             string `json:"path" valid:"-"`
    TriggerId        string `json:"triggerId" valid:"-"`
    TriggerName      string `json:"triggerName" valid:"-"`
    GroupName        string `json:"groupName" valid:"-"`
    GroupDisplayName string `json:"groupDisplayName" valid:"-"`
    FunctionName     string `json:"functionName" valid:"-"`
    TargetType       int    `json:"targetType" valid:"-"`
    TargetName       string `json:"targetName" valid:"-"`
    ServiceName      string `valid:"-"`
}

func CreateDomain(domainInfo *Domain) (*Domain, error) {
    session := models.Engine.NewSession()
    _, err := session.Table("fcs_domain").InsertOne(domainInfo)
    if err != nil {
        _ = session.Rollback()
        _ = logger.Error("Insert domainInfo err : ", err)
        return nil, err
    }
    if strings.Contains(domainInfo.Protocol, ProtocolHTTPS) {
        _, err = session.Table("fcs_cert").InsertOne(domainInfo.Cert)
        if err != nil {
            _ = session.Rollback()
            _ = logger.Error("Insert domainInfo.Cert err : ", err)
            return nil, err
        }
    }
    return domainInfo, nil
}

func UpdateDomain(domainInfo *Domain, user *resource.User) (*Domain, error) {
    session := models.Engine.NewSession()
    _, err := session.Table("fcs_domain").ID(domainInfo.Id).Where("account_id=?", user.AccountId).Cols(
        "protocol").Cols(
        "route_config").Update(domainInfo)
    if err != nil {
        _ = session.Rollback()
        _ = logger.Error("Update domain error update fcs_domain: ", err)
        return nil, err
    }
    if strings.Contains(domainInfo.Protocol, ProtocolHTTPS) {
        // 如果创建时是 HTTP，更新成 HTTP,HTTPS，那么 fcs_cert 表里不会有对应的证书数据，需要创建
        // 另一种情况就可以直接更新
        c, err := GetCertByDomainId(domainInfo.Id, user)
        if err != nil {
            _ = session.Rollback()
            _ = logger.Error("Update domain error get fcs_cert: ", err)
            return nil, err
        }
        if c != nil {
            _, err = session.Table("fcs_cert").Where("domain_id=?", domainInfo.Id).Cols(
                "name").Cols(
                "certificate").Cols(
                "key").Update(domainInfo.Cert)
            if err != nil {
                _ = session.Rollback()
                _ = logger.Error("Update domain error update fcs_cert: ", err)
                return nil, err
            }
        } else {
            _, err = session.Table("fcs_cert").InsertOne(domainInfo.Cert)
            if err != nil {
                _ = session.Rollback()
                _ = logger.Error("Update domain error insert fcs_cert: ", err)
                return nil, err
            }
        }
    }
    return domainInfo, nil
}

func DeleteDomain(id string, user *resource.User) error {
    if _, err := models.Engine.Table("fcs_domain").ID(id).Where("account_id=?", user.AccountId).Delete(new(Domain)); err != nil {
        _ = logger.Error("Delete domain err : ", err)
        return err
    }
    return nil
}

func GetDomainById(id string, user *resource.User) (*Domain, error) {
    d := &Domain{}
    if _, err := models.Engine.Table("fcs_domain").Where("account_id=?", user.AccountId).ID(id).Get(d); err != nil {
        _ = logger.Error("Get domain By Id err : ", err)
        return nil, err
    }
    if strings.Contains(d.Protocol, ProtocolHTTPS) {
        c := &Cert{}
        if _, err := models.Engine.Table("fcs_cert").Where("domain_id=?", id).Get(c); err != nil {
            _ = logger.Error("Get domain By Id find cert err : ", err)
            return nil, err
        }
        d.Cert = c
        d.CertName = d.Cert.Name
        d.CertCertificate = d.Cert.Certificate
        // TODO: 不允许通过接口获取 TLS 私钥
        d.CertKey = d.Cert.Key
    }
    return d, nil
}

func GetCertByDomainId(domainId string, user *resource.User) (*Cert, error) {
    c := &Cert{}
    exist, err := models.Engine.Table("fcs_cert").Where("domain_id=?", domainId).And("account_id=?", user.AccountId).Get(c)
    if err != nil {
        return nil, err
    }
    if !exist {
        return nil, nil
    } else {
        return c, nil
    }
}

func GetDomainList(user *resource.User, pageNo, pageSize int) (*DomainPage, error) {
    domainList := make([]*Domain, 0)
    session := models.Engine.Table("fcs_domain").OrderBy("update_time desc")
    if err := session.Find(&domainList, &Domain{A5tId: user.AccountId}); err != nil {
        _ = logger.Error("Get GetDomainList err : ", err)
        return nil, err
    }

    count := len(domainList)
    pageStart := (pageNo - 1) * pageSize
    pageEnd := pageNo * pageSize
    if pageStart > count-1 {
        pageStart = 0
        pageEnd = 0
    } else if pageEnd > count {
        pageEnd = count
    }
    domainPage := &DomainPage{
        TotalCount: int64(count),
        PageNo:     pageNo,
        PageSize:   pageSize,
        Data:       domainList[pageStart:pageEnd],
    }
    return domainPage, nil
}

func CheckDomainExist(uid, name string) (bool, error) {
    d := &Domain{}
    return models.Engine.Table("fcs_domain").Where(
        "account_id=?", uid).And(""+
        "domain_name=?", name).Exist(d)
}
